package org.bmp.zemail.server.common.services;

import java.net.URI;
import java.security.PrivateKey;
import java.util.ArrayList;
import java.util.List;
import org.bmp.zemail.cache.services.ICacheService;
import org.bmp.zemail.login.user.services.UserDao;
import org.bmp.zemail.security.services.CertService;
import org.bmp.zemail.security.services.CryptService;
import org.bmp.zemail.server.common.models.Server;
import org.bmp.zemail.server.mail.models.Mail;
import org.bmp.zemail.server.mail.services.MailService;
import org.bmp.zemail.server.folder.models.Folder;
import org.bmp.zemail.server.folder.services.ExchangeFolderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import microsoft.exchange.webservices.data.ExchangeCredentials;
import microsoft.exchange.webservices.data.ExchangeService;
import microsoft.exchange.webservices.data.ExchangeVersion;
import microsoft.exchange.webservices.data.FindItemsResults;
import microsoft.exchange.webservices.data.Item;
import microsoft.exchange.webservices.data.ItemView;
import microsoft.exchange.webservices.data.WebCredentials;
import microsoft.exchange.webservices.data.WellKnownFolderName;

@Service
public class ExchangeMailService {
	
	private static final int PAGE_SIZE = 10;
	
	/*
	 * Spring injection
	 */
	@Autowired private UserDao userDao;
	public void setUserDao(UserDao userDao) {
		this.userDao = userDao;
	}
	@Autowired private ExchangeFolderService exchangeFolderService;
	public void setExchangeFolderService(ExchangeFolderService exchangeFolderService) {
		this.exchangeFolderService = exchangeFolderService;
	}
	@Autowired private ICacheService iCacheService;
	public void setCacheService(ICacheService iCacheService) {
		this.iCacheService = iCacheService;
	}
	@Autowired private MailService mailService;
	public void setMailService(MailService mailService) {
		this.mailService = mailService;
	}

	public ExchangeService createExchangeService(Server server) {
		ExchangeService exchangeService = iCacheService.getExchangeServiceList().get(server.getId());
		
		//verifies if the server exists and is already connected
		if (exchangeService == null) {
			
			//decode the password
			byte[] encodedPrivateKey = userDao.getUserPrivateKey(server.getUser().getUsername());
			PrivateKey userPrivKey = CertService.getPrivateKey(encodedPrivateKey);
			byte[] decodedPassword = CryptService.decrypt(server.getCredentials().getEncryptedPassword(),
					userPrivKey);
			
			//set version and credentials
			exchangeService = new ExchangeService(ExchangeVersion.Exchange2007_SP1);
			ExchangeCredentials credentials = new WebCredentials(server.getCredentials().getUsername(),
					new String (decodedPassword));
			exchangeService.setCredentials(credentials);
			
			//try to connect
			try {
				exchangeService.setUrl(new URI(server.getUrl()));
			} catch (Exception e) {
				//TODO BM log error (no conectivity ?) and quit
				e.printStackTrace();
			}
		}
		
		//insert exchange service in map
		iCacheService.updateExchangeServiceListCache(server.getId(), exchangeService);
		
		return exchangeService;
	}
	
	public void setFolders (Server server) {
		List<Folder> folders = new ArrayList<Folder>();
			
		//for each Well Known folder create a Folder object
		for(String folderName : exchangeFolderService.getFolderList()) {
			Folder folder = new Folder();
	    	folder.setName(folderName);
	    	folders.add(folder);
	    }
			
		server.setFolders(folders);
	}
	
	public void setNextPage (Server server, String folder, String action) {
		List<Mail> mails = new ArrayList<Mail>();
		
		//get server
		ExchangeService exchangeMailService = iCacheService.getExchangeServiceList().get(server.getId());
		
		//get the instance of the folder
		Folder serverFolder = server.getFolder(folder);
		
		//validates if folder exists on server
		if (serverFolder.getName() == null) {
			//TODO BM problemas
			return;
		}
		
		//validates if server is connected
		if (exchangeMailService == null) {
			//TODO BM problemas
			return;
		}
		
		if (MailService.ACTION_NEXT.equals(action)) {
			serverFolder.incrementPage();
		} else if (MailService.ACTION_PREVIOUS.equals(action)) {
			serverFolder.decrementPage();
		} else {
			serverFolder.resetPage();
		}
		
		//create a view into the folder
		ItemView view = new ItemView(ExchangeMailService.PAGE_SIZE);
		view.setOffset(serverFolder.getPage() * ExchangeMailService.PAGE_SIZE);
		
		//try and get the mails from the servers folder
		//TODO BM implement get mails for all folders
		FindItemsResults<Item> findResults;
		try {
			if (getWellKnownFolder(folder) != null) {
				//findResults = exchangeService.findItems(getWellKnownFolder(folder), view);
			}
			microsoft.exchange.webservices.data.Folder exchangeFolder 
				= microsoft.exchange.webservices.data.Folder.bind(exchangeMailService, getWellKnownFolder(folder));
			findResults = exchangeMailService.findItems(exchangeFolder.getId(), view);
			serverFolder.setId(exchangeFolder.getId().getUniqueId());
			
			//create the mails objects
			for(Item item : findResults.getItems()) {
				Mail mail = mailService.getMail(item, exchangeMailService);
				if (mail != null) {
					mails.add(mail);
				} else {
					//TODO BM problemas
				}
			}
		} catch (Exception e) {
			// TODO BM problemas
			e.printStackTrace();
		}
		
		//set mails and increment page
		serverFolder.setMails(mails);
	}
	
	private WellKnownFolderName getWellKnownFolder (String folder) {
		if (folder.equals(ExchangeFolderService.INBOX)) {
			return WellKnownFolderName.Inbox;
		} else if (folder.equals(ExchangeFolderService.SENT)) {
			return WellKnownFolderName.SentItems;
		} else if (folder.equals(ExchangeFolderService.JUNK)) {
			return WellKnownFolderName.JunkEmail;
		} else if (folder.equals(ExchangeFolderService.DELETED)) {
			return WellKnownFolderName.DeletedItems;
		} else if (folder.equals(ExchangeFolderService.DRAFTS)) {
			return WellKnownFolderName.Drafts;
		} else {
			return null;
		}
	}
}
